package cmd

import (
	"fmt"
	mqtt "github.com/eclipse/paho.mqtt.golang"
	"github.com/google/uuid"
	"github.com/spf13/cobra"
	global2 "longmen/server/config/global"
	mqtt2 "longmen/server/internal/services/nami/api/mqtt"
	"longmen/server/internal/services/nami/config"
	"os"
	"os/signal"
	"sync"
	"syscall"
	"time"
)

var mqttHandlers []mqtt2.MQHandler
var onceInitMqttHandlers sync.Once

// WARN: can't call in init(), won't work,
func initMqttHandlers() {
	/* init mqtt handlers */
	if config.NamiFootballEnabled() {
		global2.Log.Debugf("[足球] mqtt enabled")
		mqttHandlers = append(mqttHandlers, &mqtt2.FootBallMQ{})
	}
	if config.NamiBasketballEnabled() {
		global2.Log.Debugf("[篮球] mqtt enabled")
		mqttHandlers = append(mqttHandlers, &mqtt2.BasketBallMQ{})
	}
	if config.NamiCricketEnabled() {
		global2.Log.Debugf("[板球] mqtt enabled")
		mqttHandlers = append(mqttHandlers, &mqtt2.CricketMQ{})
	}
}

var clientID = ""
var messagePubHandler mqtt.MessageHandler = func(client mqtt.Client, msg mqtt.Message) {
	global2.Log.Warnf("Received message: %s from topic: %s\n", msg.Payload(), msg.Topic())
}

var connectHandler mqtt.OnConnectHandler = func(client mqtt.Client) {
	global2.Log.Info("Connected :%v", client.IsConnected())
	if client.IsConnected() {
		onceInitMqttHandlers.Do(func() {
			initMqttHandlers()
		})
		for i := 0; i < len(mqttHandlers); i++ {
			mqttHandlers[i].InitTopic(client)
		}
	}
}

var connectLostHandler mqtt.ConnectionLostHandler = func(client mqtt.Client, err error) {
	global2.Log.Errorf("Connect lost: %v", err)
}
var reconnectHandler mqtt.ReconnectHandler = func(client mqtt.Client, op *mqtt.ClientOptions) {
	global2.Log.Errorf(" reconnecting current is connected ? : %v", client.IsConnected())
}
var syncMQTT = &cobra.Command{
	Use:   "mqtt",
	Short: "运行MQTT客户端订阅",
	Long:  "实时数据同步",
	Run: func(cmd *cobra.Command, args []string) {
		StartSub()
	},
	PreRun: func(cmd *cobra.Command, args []string) {
		global2.AppName = "crontab_mqtt"
		global2.Initialize(configFile)
		config.InitConfig()
		clientID = getRandomClientId("mqtt_nami_")
		err := global2.InitElasticSearch()
		if err != nil {
			global2.Log.Fatalf("%s", err.Error())
		}
	},
}

// getRandomClientId returns randomized ClientId.
func getRandomClientId(prefix string) string {
	u := uuid.New()
	return prefix + u.String()
}
func StartSub() {

	opts := mqtt.NewClientOptions()
	mqttConf := config.Nami.MQTT
	url := fmt.Sprintf("%s://%s:%d/mqtt", mqttConf.Protocol, mqttConf.Broker, mqttConf.Port)
	global2.Log.Info("connect : ", url, " clientId ", clientID)
	opts.AddBroker(url)
	opts.SetClientID(clientID)
	opts.SetUsername(config.Nami.User)
	opts.SetPassword(config.Nami.Key)
	opts.SetConnectTimeout(10 * time.Second)
	opts.SetCleanSession(false)
	opts.SetPingTimeout(3 * time.Second)
	opts.SetKeepAlive(20 * time.Second)
	opts.SetConnectRetry(true)
	//opts.SetDefaultPublishHandler(messagePubHandler)
	opts.OnConnect = connectHandler
	opts.OnConnectionLost = connectLostHandler
	opts.SetAutoReconnect(true)
	opts.SetMaxReconnectInterval(3 * time.Second)
	opts.SetReconnectingHandler(reconnectHandler)
	opts.SetOrderMatters(false)
	client := mqtt.NewClient(opts)
	if token := client.Connect(); token.Wait() && token.Error() != nil {
		global2.Log.Panic(token.Error())
	}
	//pyroscope.InitPyroScope("nami_mqtt")
	//创建监听退出chan
	c := make(chan os.Signal, 1)
	//监听指定信号 ctrl+c kill
	signal.Notify(c, syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT, syscall.SIGUSR1, syscall.SIGUSR2)
	for s := range c {
		switch s {
		case syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT:
			global2.Log.Info("退出信号： ", s)
			for i := 0; i < len(mqttHandlers); i++ {
				mqttHandlers[i].Quit(client)
			}
			client.Disconnect(5000)
			os.Exit(0)
		default:
			global2.Log.Info("未知信号", s)
		}
	}
}
